use crate::resolver::cli_args::CliArgs;
use crate::resolver::config::Config;
use crate::resolver::history_struct::{ChangelogHistory, Commit, Section, Version};
use crate::resolver::Resolver;
use git2::Repository;
use std::env::current_dir;
use std::path::PathBuf;
use std::{fs, process};
use tracing::trace;
use wang_utils::core::resolve_file_path;
use wang_utils::git::{git_read_commits, GitCommit};

impl Resolver {
    pub fn init(cli_args: CliArgs) -> anyhow::Result<Self> {
        let mut cli_args = cli_args;
        trace!("初始化解析器 cli_args: {:?}", &cli_args);
        //解析path
        let path = resolve_path(&mut cli_args)?;
        trace!("初始化path后 path:{:?}", path);
        //解析config配置文件
        let config = resolve_config_file(&mut cli_args)?;
        trace!("初始化config后 config:{:?}", config);
        let history = resolve_init_history(&mut cli_args, config.clone())?;
        trace!("初始化history后 history:{:?}", history);
        Ok(Self {
            cli_args,
            path,
            config,
            history,
        })
    }
    pub fn resolve(&mut self) -> anyhow::Result<()> {
        let repo = Repository::open(&self.path)?;
        // 读取git历史记录
        let commits = git_read_commits(&repo)?;
        trace!("解析commits:{commits:?}");
        for mut commit in commits {
            self.resolve_version(&mut commit);
            self.resolve_section(&mut commit);
        }
        Ok(())
    }
    pub fn resolve_section(&mut self, commit: &mut GitCommit) {
        let message = &commit.message;
        // 拿到类别名称
        let section_name = match message.find(":") {
            Some(idx) => {
                let mut section_type_end = idx;
                if message.chars().nth(idx - 1).unwrap_or(' ').is_whitespace() {
                    section_type_end -= 1;
                }
                let section = &message[..section_type_end];
                if section.ends_with('!') {
                    Some("break".to_string())
                } else {
                    Some(section.to_string())
                }
            }
            None => None,
        };
        // 判断有没有类别
        if section_name.is_none() {
            // 如果没有类别则直接返回
            return;
        }
        let section_name = section_name.unwrap();
        // 判断类别是否在配置中
        if !self
            .config
            .types
            .as_ref()
            .unwrap()
            .iter()
            .any(|t| t.type_ == section_name && !t.hidden)
        {
            // 如果配置中没有该类别则直接返回
            return;
        }
        // 拿到最新的版本
        let version = self.history.versions.last_mut().unwrap();
        // 拿到最新的类别
        let section = if let Some(section) = version
            .sections
            .iter_mut()
            .find(|s| s.section == section_name)
        {
            section
        } else {
            // 如果没有找到类别则新建一个
            let section = Section {
                section: section_name,
                commits: vec![],
            };
            version.sections.push(section);
            version.sections.last_mut().unwrap()
        };
        // 截取提交信息中的有效信息
        let message = if let Some(idx) = commit.message.find(": ") {
            &commit.message[(idx + 2)..]
        } else {
            &commit.message
        };
        let commit = Commit {
            id: commit.commit_id.to_string(),
            message: message.to_string(),
            time: commit.time,
        };
        section.commits.push(commit);
    }
    pub fn resolve_version(&mut self, commit: &mut GitCommit) {
        if let Some(tag) = commit.tag.take() {
            let version = Version {
                name: tag,
                time: commit.time,
                sections: vec![],
            };
            self.history.versions.push(version);
        } else {
            if self.history.versions.len() == 0 {
                let version = Version {
                    name: "None".to_string(),
                    time: commit.time,
                    sections: vec![],
                };
                self.history.versions.push(version);
            }
        }
    }
}
fn resolve_path(cli_args: &mut CliArgs) -> anyhow::Result<PathBuf> {
    trace!("解析path path:{:?}", cli_args.path);
    let absolute_path = if let Some(p) = &cli_args.path {
        resolve_file_path(p)?
    } else {
        current_dir()?
    };
    trace!("解析path absolute_path:{:?}", absolute_path);
    Ok(absolute_path)
}
fn resolve_config_file(cli_args: &mut CliArgs) -> anyhow::Result<Config> {
    let origin_config_content = include_str!("../files/config.json");
    if cli_args.generate_config {
        let path = cli_args.path.as_ref().unwrap();
        let path = PathBuf::from(path).join(".versionrc");
        fs::write(path, origin_config_content)?;
        println!("生成配置文件.versionrc成功！");
        process::exit(0);
    }
    trace!("解析配置文件 cli_args:{:?}", cli_args);
    if cli_args.config_file.is_none() {
        let config = serde_json::from_str::<Config>(origin_config_content)?;
        return Ok(config);
    }
    let config_file_path = cli_args.config_file.as_ref().unwrap();
    let config_file_path = resolve_file_path(config_file_path)?;
    let config_file_content = fs::read_to_string(&config_file_path)?;
    let mut config =
        serde_json::from_str::<Config>(&config_file_content).unwrap_or_else(move |e| {
            println!(
                "配置文件:[{config_file_path:?}]解析失败，错误信息:[{}],请检查是否不符合json格式",
                e.to_string()
            );
            process::exit(1);
        });
    let origin_config = serde_json::from_str::<Config>(origin_config_content)?;

    if config.title.is_none() {
        config.title = origin_config.title;
    }
    if config.desc.is_none() {
        config.desc = origin_config.desc;
    }
    if config.types.is_none() {
        config.types = origin_config.types;
    }
    trace!("配置 config:{config:?}");
    Ok(config)
}
fn resolve_init_history(
    cli_args: &mut CliArgs,
    config: Config,
) -> anyhow::Result<ChangelogHistory> {
    let title = cli_args.title.take().unwrap_or("更新日志".to_string());
    let desc = cli_args.desc.take().unwrap_or(
        "该日志由wang-changelog生成，详情见 https://gitee.com/consolelog/wang-changelog"
            .to_string(),
    );
    Ok(ChangelogHistory {
        title,
        desc,
        versions: vec![],
        config,
        rev_commit: cli_args.rev_commit,
    })
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::utils::test_utils::{setup_with_commits_json, teardown_git};
    #[test]
    fn test_resolve() -> anyhow::Result<()> {
        let test_folder = setup_with_commits_json("tests/test_commits/test1.json")?;
        let mut args = CliArgs::new();
        args.path = Some(test_folder.to_string());
        let mut resolver = Resolver::init(args)?;
        // 解析git历史
        resolver.resolve()?;
        assert_eq!(5, resolver.history.versions.len());
        assert_eq!(0, resolver.history.versions[0].sections.len());
        teardown_git(&test_folder);
        Ok(())
    }
}
